#pragma once
#include <iostream>
#include <string>
#include <pthread.h>
#include <fstream>
#include <vector>
#include <sstream>
#include <sys/types.h>
#include <sys/socket.h>
#include <unordered_map>
#include <thread>

#include "Socket.hpp"
#include "Log.hpp"

const std::string webroot = "./webroot"; // web 根目录
const std::string sep = "\r\n";
const std::string blank_line = "\r\n";
const std::string homepage = "index.html";

class HttpRequest
{
public:
    void Deserialize(std::string req) // 反序列化
    {
        while (true)
        {
            std::size_t pos = req.find(sep);
            if (pos == std::string::npos)
                break;
            std::string temp = req.substr(0, pos);
            if (temp.empty())
                break;
            _req_header.push_back(temp);
            req.erase(0, pos + sep.size());
        }
        _text = req;
    }
    // .png:image/png
    void Parse() // 解析请求报文
    {
        std::stringstream ss(_req_header[0]);
        ss >> _method >> _url >> _http_version;
        _file_path = webroot; // ./webroot
        if (_url == "/" || _url == "/index.html")
        {
            _file_path += "/";
            _file_path += homepage; // ./webroot/index.html
        }
        else
            _file_path += _url; // /xxxx.html->./wwwroot/xxxx.html

        auto pos = _file_path.rfind(".");
        if (pos == std::string::npos)
            _suffix = ".html";
        else
            _suffix = _file_path.substr(pos);
    }
    void DebugPrint()
    {
        for (auto &line : _req_header)
        {
            std::cout << "--------------------------------" << std::endl;
            std::cout << line << "\n\n";
        }

        std::cout << "method: " << _method << std::endl;
        std::cout << "url: " << _url << std::endl;
        std::cout << "http_version: " << _http_version << std::endl;
        std::cout << "file_path: " << _file_path << std::endl;
        std::cout << _text << std::endl;
    }

public:
    std::vector<std::string> _req_header;
    std::string _text;

    // 解析之后的结果
    std::string _method;       // 请求报文方法
    std::string _url;          // 域名
    std::string _http_version; // http版本
    std::string _file_path;    // ./wwwroot/a/b/c.html 2.png
    std::string _suffix;       //
};

class Httpserve
{
public:
    Httpserve(uint16_t port)
        : _port(port)
    {
        _content_type.insert({".html", "text/html"});
        _content_type.insert({".png", "image/png"});
    }
    ~Httpserve()
    {
        _listensock.Close();
    }

    static std::string ReadHtmlContent(const std::string &htmlpath) // 读取请求报文内容
    {
        // 坑
        // std::ifstream in(htmlpath, std::ios::binary); //读的方式拿去
        // if (!in.is_open())
        //     return "";

        // in.seekg(0, std::ios_base::end);
        // auto len = in.tellg();
        // in.seekg(0, std::ios_base::beg);

        // std::string content;
        // content.resize(len);

        // in.read((char *)content.c_str(), content.size());

        // 1 普通的文本读取
        //std::cout << htmlpath << std::endl;
        //std::string content;
        // std::string line;
        // //std::cout << "#1" << std::endl;
        // while (std::getline(in, line)) // 文本行读取
        // {
        //     content += line;
        //     //std::cout << content << std::endl;
        // }
        // 2 读取字节
        std::ifstream in(htmlpath, std::ios::binary); //二进制读取,避免文件内容出现遗失
        if (!in.is_open())
        {
            //std::cout << "#2" << std::endl;
            return "";
        }
        std::string content((std::istreambuf_iterator<char>(in)), std::istreambuf_iterator<char>());  // 读取的内容
        if (!in.eof() && in.fail()) //检查读取是否错误
        {
            std::cout << "读取文件时发生错误" << std::endl;
            return "";
        }
        //std::cout << content << std::endl;
        in.close();
        return content;
    }
    std::string SuffixToDesc(const std::string &suffix)
    {
        auto iter = _content_type.find(suffix);
        if (iter == _content_type.end())
            return _content_type[".html"];
        else
            return _content_type[suffix];
    }

    bool Start()
    {
        _listensock.Socket();
        _listensock.Bind(_port);
        _listensock.Listen();
        for (;;)
        {
            std::string clientip;
            uint16_t clientport;
            int sockfd = _listensock.Accept(&clientip, &clientport);
            lg(Info, "Get a new link...sockfd: %d", sockfd);
            std::thread t1([this, sockfd]()
                           {
                char buffer[10240]; //缓冲区
                ssize_t n = recv(sockfd, buffer, sizeof(buffer), 0); //0默认行文和read一致
                if(n > 0)
                {
                    buffer[n] = 0;
                    //std::cout << buffer;

                    //响应：
                    //1、解析：
                    HttpRequest req;
                    req.Deserialize(buffer);
                    req.Parse(); //解析请求报文
                    //req.DebugPrint();
                    
                    std::string text; //响应的正文部分
                    bool ok = true; //标记读取文件是否成功
                    // std::cout << "@ "<<req._file_path << std::endl;
                    text = ReadHtmlContent(req._file_path); // 失败？
                    if(text.empty())
                    {
                        ok = false;
                        //std::cout << "&1" << std::endl;
                        std::string err_html = webroot;
                        err_html += "/";
                        err_html += "err.html";
                        text = ReadHtmlContent(err_html);
                    }

                    std::string response_line;
                    if(ok)
                        response_line = "HTTP/1.0 200 OK\r\n";
                    else
                        response_line = "HTTP/1.0 404 Not Found\r\n";

                    //text = ReadHtmlContent(req._file_path); //读取文件内容
                    //std::string response_line = "HTTP/1.1 200 OK\r\n";
                    std::string response_header = "Content-Length: ";
                    response_header += std::to_string(text.size()); // Content-Length: 11
                    response_header += sep;
                    response_header += "Content-Type: ";
                    response_header += SuffixToDesc(req._suffix);
                    //std::cout << "@2";
                    response_header += sep;
                    response_header += "Connection: keep-alive";
                    response_header += sep;
                    response_header += "Set-Cookie: name=haha&&passwd=12345";
                    response_header += sep;


                    
                    //response_line = "HTTP/1.0 302 Found\r\n";
                    // std::string response_header = "Content-Length: ";
                    // response_header += std::to_string(text.size()); // Content-Length: 11
                    // response_header += "\r\n";
                    // response_header += "Content-Type: ";
                    // response_header += SuffixToDesc(req._suffix);
                    // response_header += "\r\n";
                    // response_header += "Set-Cookie: name=haha&&passwd=12345";
                    // response_header += "\r\n";

                    // //response_header += "Location: https://www.qq.com\r\n";
                    // std::string blank_line = "\r\n"; // \n

                    std::string response = response_line;
                    response += response_header;
                    response += blank_line;
                    response += text;
                    //std::cout << text << std::endl;
                    //std::cout << "@ 1" << std::endl;

                    send(sockfd, response.c_str(), response.size(), 0);
                }
                close(sockfd); });
            t1.detach(); // 线程分离
        }
    }

private:
    Sock _listensock;
    uint16_t _port;
    std::unordered_map<std::string, std::string> _content_type;
};